﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;

using Holidays.CountryCalculators;

namespace Holidays.CountryCalculators {

	public abstract class BaseCalculator {

		public abstract Boolean IsWeekend(DateTime date);
		protected abstract Boolean IsDynamicHoliday(DateTime date, XDocument holidayData);

		public virtual Boolean IsHoliday(DateTime date, XDocument holidayData) {
			IEnumerable<XElement> specificDays = holidayData.Root.Elements("Date")
										.Where(d =>
												d.Attribute("Type").Value == "static" &&
												d.Attribute("Month").Value == date.Month.ToString() &&
												d.Attribute("Day").Value == date.Day.ToString() &&
												(d.Attribute("StartYear") == null || Int32.Parse(d.Attribute("StartYear").Value) <= date.Year) &&
												(d.Attribute("EndYear") == null || Int32.Parse(d.Attribute("EndYear").Value) >= date.Year) &&
												d.Attribute("Holiday").Value == "true"
											);

			return specificDays.Any() ? true : this.IsDynamicHoliday(date, holidayData);
		}

		public virtual Boolean IsHoliday(DateTime date) {
			String currentCulture = CultureInfo.CurrentCulture.Name;
			XDocument holidaysXml = ResourceFactory.GetHolidayData(currentCulture);
			return this.IsHoliday(date, holidaysXml);
		}

		public virtual Boolean IsWorkday(DateTime date) {
			return !this.IsHoliday(date) && !this.IsWeekend(date);
		}

		public virtual Int32 VacationYear(DateTime date) {
			return date.Year;
		}

		protected virtual Dictionary<String, DateTime> GetBaseDates(XDocument holidayData, DateTime date) {
			IEnumerable<String> baseCalculators = holidayData.Root.Elements("Date")
													.Where(d =>
														d.Attribute("Type").Value == "dynamic" &&
														d.Attribute("Holiday").Value == "true" &&
														(d.Attribute("StartYear") == null || Int32.Parse(d.Attribute("StartYear").Value) <= date.Year) &&
														(d.Attribute("EndYear") == null || Int32.Parse(d.Attribute("EndYear").Value) >= date.Year) &&
														d.Attribute("Holiday").Value == "true")
													.Select(d => d.Attribute("Base").Value)
													.Distinct();

			Dictionary<String, DateTime> output = new Dictionary<String, DateTime>();
			foreach (String baseType in baseCalculators) {
				switch (baseType) {
					case "EasterGauss":
						output.Add(baseType, date.Easter(EasterAlgorithm.Gauss));
						break;
					case "EasterMeeusJonesButcher":
						output.Add(baseType, date.Easter(EasterAlgorithm.MeeusJonesButcher));
						break;
					default:
						throw new NotImplementedException(baseType);
				}
			}

			return output;
		}
	}
}